﻿using DevZest.Windows.Docking;
using IDE;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;

namespace neside2
{
    class IDEManager : IDE.I_IDE
    {
        DockControl dockControl;
        Menu menu;
        ToolBarTray toolbarTray;

        public IDEManager(DockControl dockControl, Menu menu, ToolBarTray toolbarTray)
        {
            this.dockControl = dockControl;
            this.dockControl.ActiveDocumentChanged += (s, e) =>
              {
                  if (this.dockControl.ActiveDocument != null)
                  {
                      var doc = this.dockControl.ActiveDocument.Tag as IDE.IDocument;
                      this.curFile = doc.Filename.ToLower();
                  }
              };
            this.menu = menu;
            this.toolbarTray = toolbarTray;
        }

        ////////////////////////////////////////////////////////////////////////
        ////IDE插件系统
        /// <summary>
        /// 
        /// </summary>
        Dictionary<string, IDE.IPlugin> plugins = new Dictionary<string, IDE.IPlugin>();
        Dictionary<string, FileInfo> filemap = new Dictionary<string, FileInfo>();
        Dictionary<string, Dictionary<string, PanelInfo>> plugin_panels = new Dictionary<string, Dictionary<string, PanelInfo>>();
        Dictionary<string, DocInfo> opendocs = new Dictionary<string, DocInfo>();
        class FileInfo
        {
            public IDE.FileTypeDesc type;
            public string pluginname;
        }
        class PanelInfo
        {
            public IDE.PanelInfo panelInfo;
            //public UIElement UIElement;不用缓存，搞新的
            public DockItem dockItem;
        }
        class DocInfo
        {
            public IDE.IDocument document;
            public DockItem dockItem;
            public bool Change;
        }

        public void RegPlugin(IDE.IPlugin plugin)
        {
            plugins.Add(plugin.Name, plugin);
            if (plugin.filetypes != null)
            {
                foreach (var f in plugin.filetypes)
                {
                    filemap.Add(f.extname.ToLower(), new FileInfo() { type = f, pluginname = plugin.Name });
                }
            }
            plugin.IDE = this;
        }

        //要用activate 不要用focus
        bool IDE.I_IDE.OpenFile(string fullfilename, bool writeable)
        {
            var ext = System.IO.Path.GetExtension(fullfilename).ToLower();
            var key = (fullfilename).ToLower();
            if (opendocs.TryGetValue(key, out DocInfo info))
            {
                if (info.dockItem.IsHidden)
                    info.dockItem.Show(dockControl);
                else
                    info.dockItem.Activate();

                this.curFile = key;
                return true;
            }
            else
            {
                DockItem _item = null;

                if (this.filemap.ContainsKey(ext))
                {
                    var finfo = this.filemap[ext];
                    _item = CreateDocument(ext, finfo.pluginname, fullfilename, writeable);
                }
                else
                {
                    _item = CreateDocument(ext, "_default_", fullfilename, writeable);
                }
                if (_item == null)
                    return false;
                _item.Show(dockControl, DevZest.Windows.Docking.DockPosition.Document);


                this.curFile = key;
                return true;
            }
        }
        bool IDE.I_IDE.ShowPanel(string pluginname, string paneltype)
        {
            if (plugin_panels.ContainsKey(pluginname) == false)
                return false;
            var panels = plugin_panels[pluginname];
            if (panels.ContainsKey(paneltype) == false)
                return false;
            var panel = panels[paneltype];


            if (panel.dockItem != null)
            {
                if (panel.dockItem.IsHidden)
                {
                    panel.dockItem.Show(dockControl);
                }
                else
                {
                    panel.dockItem.Activate();
                }
            }
            else
            {
                var item = CreatePanel(pluginname, paneltype);
                item.Show(dockControl, DevZest.Windows.Docking.DockPosition.Floating);
            }
            //plug.panels
            return true;
        }
        DockItem CreatePanel(string pluginname, string paneltype)
        {
            var plug = plugins[pluginname];
            var panel = plugin_panels[pluginname][paneltype];

            var item = new DockItemMy();
            item.pluginName = pluginname;
            item.panelType = paneltype;
            item.TabText = item.Title = panel.panelInfo.title;
            //这个不能设置。。。
            //item.Width = panel.panelInfo.defaultWidth;
            //item.Height = panel.panelInfo.defaultHeight;

            //这个wpfdocking 不走寻常路， 之前用unload方法不对，会多触发。
            //closing 默认走hide，hide又没有事件通知
            // item.HideOnPerformClose = false;
            //关了hide 有bug 这品质真卧槽啊

            //只能打开hide，如果close了走closeing，否则 hide show
            //这个品质太卧槽了
            item.Closing += (s, e) =>
              {
                  panel.dockItem = null;
                  // panel.UIElement = null;
              };
            panel.dockItem = item;
            //panel.UIElement = plug.CreatePanelUI(paneltype);
            item.Content = plug.CreatePanelUI(paneltype);
            return item;
        }
        DockItem CreateDocument(string extname, string pluginname, string filename, bool writeable)
        {
            var key = (filename).ToLower();
            var info = new DocInfo();
            opendocs[key] = info;

            var plug = plugins[pluginname];
            var doc = plug.OpenFile(extname, filename, true);

            var item = new DockItemFile();

            item.pluginName = pluginname;
            item.extName = extname;
            item.filename = filename;
            item.writeable = writeable;
            if (writeable)
            {
                doc.Change += () =>
                  {
                      info.Change = true;
                      if (item.TabText.IndexOf("[*]") != 0)
                      {
                          item.TabText = item.Title = "[*]" + item.TabText;
                      }
                  };
            }
            item.TabText = item.Title = System.IO.Path.GetFileName(filename);
            item.Content = doc.Editor;
            item.Tag = doc;

            info.document = doc;
            info.dockItem = item;
            return item;
        }
        ////////////////////////////////////////////////////////////////////////////
        //IDE UI逻辑
        /// <summary>
        /// 
        /// </summary>
        MenuItem MenuItemLayout;
        MenuItem MenuItemToolbar;
        public void Start()
        {
            ///////////////////////////////////////////menu init
            MenuItemLayout = new MenuItem();
            MenuItemLayout.Header = "Layout";
            menu.Items.Add(MenuItemLayout);

            var LayoutLoad = new MenuItem();
            LayoutLoad.Header = "LoadLayout";
            LayoutLoad.Click += (s, e) =>
              {
                  this.LoadLayout();
              };
            MenuItemLayout.Items.Add(LayoutLoad);
            var LaoutSave = new MenuItem();
            LaoutSave.Header = "SaveLayout";
            LaoutSave.Click += (s, e) =>
            {
                this.SaveLayout();
            };
            MenuItemLayout.Items.Add(LaoutSave);
            MenuItemLayout.Items.Add(new Separator());

            //初始化创建面板菜单
            foreach (var p in plugins.Values)
            {
                if (p.panels != null)
                {
                    plugin_panels[p.Name] = new Dictionary<string, PanelInfo>();

                    foreach (var panel in p.panels)
                    {
                        PanelInfo pinfo = new PanelInfo();
                        pinfo.panelInfo = panel;
                        plugin_panels[p.Name][panel.type] = pinfo;

                        MenuItem showPanel = new MenuItem();
                        showPanel.Header = "Open " + p.Name + ":" + panel.type;
                        showPanel.Click += (s, e) =>
                        {
                            (this as IDE.I_IDE).ShowPanel(p.Name, panel.type);
                        };
                        MenuItemLayout.Items.Add(showPanel);

                    }
                }
            }

            //初始化插件自定义菜单
            foreach (var p in plugins.Values)
            {
                if (p.MenuItem != null)
                {
                    foreach (var m in p.MenuItem)
                    {
                        string path = m.menuPath;

                        if (m.menuType == IDE.MenuOption.MenuType.Custom)
                        {
                            InitMenu(path, m.customMenu);
                        }
                        else
                        {
                            var menu = new MenuItem();
                            menu.Click += (s, e) =>
                              {
                                  p.OnMenuClick(path);
                              };
                            InitMenu(path, menu);

                        }
                    }
                }
            }


            MenuItemToolbar = new MenuItem();
            MenuItemToolbar.Header = "ToolBar";
            menu.Items.Add(MenuItemToolbar);

            //初始化插件自定义Toolbar
            foreach (var p in plugins.Values)
            {
                if (p.toolbars != null)
                {
                    foreach (var tb in p.toolbars)
                    {
                        ToolBar thisbar = tb;
                        var menucheck = new MenuItem();
                        menucheck.Header = p.Name + " - " + tb.Name;
                        menucheck.Click += (s, e) =>
                          {
                              menucheck.IsChecked = !menucheck.IsChecked;
                              if (menucheck.IsChecked)
                              {
                                  thisbar.Visibility = Visibility.Visible;
                              }
                              else
                              {
                                  thisbar.Visibility = Visibility.Hidden;
                              }
                          }
                        ;
                        //menucheck.IsCheckable = true;
                        menucheck.IsChecked = true;
                        MenuItemToolbar.Items.Add(menucheck);

                        this.toolbarTray.ToolBars.Add(tb);
                    }
                }
            }
            LoadLayout();
        }

        void InitMenu(string path, MenuItem item)
        {
            var pathsub = path.Split('\\', '/');
            item.Header = pathsub[pathsub.Length - 1];
            var paths = pathsub.Take(pathsub.Length - 1).ToArray();
            var pmenu = GetMenu(this.menu.Items, paths);


            pmenu.Items.Add(item);
        }
        MenuItem GetMenu(ItemCollection menucoll, string[] paths)
        {
            foreach (MenuItem m in menucoll)
            {
                if ((string)m.Header == paths[0])
                {
                    if (paths.Length == 1)
                    {
                        return m;
                    }
                    else
                    {
                        return GetMenu(m.Items, paths.Skip(1).ToArray());
                    }
                }
            }
            MenuItem smenu = new MenuItem();
            smenu.Header = paths[0];
            menucoll.Add(smenu);
            if ((paths.Length == 1))
                return smenu;
            return GetMenu(smenu.Items, paths.Skip(1).ToArray());
        }

        void SaveLayout()
        {
            //这个插件自己的 Save Load 机制 简直 SB的不行
            //采用无需破坏的修改方式，来完成布局
            //1.Save继承
            //2.Load Clear掉Hiddle操作
            var layout = dockControl.Save();

            var str = XamlWriter.Save(layout);
            System.IO.File.WriteAllText("layout.xaml", str);
        }
        void LoadLayout()
        {
            //清理布局相关功能
            foreach (var panels in plugin_panels.Values)
            {
                foreach (var p in panels.Values)
                {
                    p.dockItem = null;
                }
            }
            opendocs.Clear();

            try
            {
                var str = System.IO.File.ReadAllText("layout.xaml");
                var layout = (DockLayout)XamlReader.Parse(str);
                //清理掉隐藏action,这里有Bug
                List<ShowAction> removed = new List<ShowAction>();
                foreach (var i in layout.ShowActions)
                {
                    if (i.ShowMethod == DockItemShowMethod.Hide)
                    {
                        removed.Add(i);
                    }
                }
                foreach (var r in removed)
                {
                    layout.ShowActions.Remove(r);
                }

                //close all item
                for (int i = dockControl.DockItems.Count - 1; i >= 0; i--)
                {
                    DockItem item = dockControl.DockItems[i];
                    item.Close();
                }

                dockControl.Load(layout, (o) =>
                {
                    var item = o as DockItem;
                    if (item != null)
                        return item;

                    var tag1 = o as string[];
                    if (tag1 != null && tag1[0] == "DockInfo")
                    {
                        return CreatePanel(tag1[1], tag1[2]);
                    }

                    return null;
                });
            }
            catch (Exception err)
            {
                System.Diagnostics.Debug.WriteLine("error LoadLayout:" + err.Message);
            }
        }
        ///////////////////////////////////////////////////////////
        //插件标准通讯手段设计
        bool I_IDE.HasPlugin(string pluginname)
        {
            return plugins.ContainsKey(pluginname);
        }

        class Pipeline : IPileLine
        {
            event Action<string, string> onRecv;
            event Action<string, byte[]> onRecvBin;
            public void Care(Action<string, string> onRecv, Action<string, byte[]> onRecvBin)
            {
                if (onRecv != null)
                    this.onRecv += onRecv;
                if (onRecvBin != null)
                    this.onRecvBin += onRecvBin;
            }

            public void Send(string tag, string arg)
            {
                onRecv?.Invoke(tag, arg);
            }

            public void SendBin(string tag, byte[] arg)
            {
                onRecvBin?.Invoke(tag, arg);
            }
        }
        Dictionary<string, Pipeline> pipelines = new Dictionary<string, Pipeline>();
        IPileLine I_IDE.GetPipeline(string name)
        {
            var key = name.ToLower();
            if (pipelines.TryGetValue(key, out Pipeline value))
            {
                return value;
            }
            else
            {
                Pipeline p = new Pipeline();
                pipelines[key] = p;
                return p;
            }
        }

        /// //////////////////////////////////////////////////
        /// 共享数据
        Dictionary<string, string> namedString = new Dictionary<string, string>();
        Dictionary<string, byte[]> namedBytes = new Dictionary<string, byte[]>();

        public string curFile
        {
            get;
            set;
        }

        void I_IDE.SetData_ByteArray(string key, byte[] data)
        {
            namedBytes[key] = data;
        }

        byte[] I_IDE.GetData_ByteArray(string key)
        {
            if (namedBytes.ContainsKey(key) == false)
                return null;
            return namedBytes[key];
        }

        void I_IDE.SetData_String(string key, string data)
        {
            namedString[key] = data;
        }

        string I_IDE.GetData_String(string key)
        {
            if (namedString.ContainsKey(key) == false)
                return null;
            return namedString[key];
        }
        private void  SaveFile(string filename)
        {
            var key = filename.ToLower();
            if (opendocs.TryGetValue(key, out DocInfo info))
            {
                if (info.Change)
                {
                    if (info.document.Save())
                    {
                        info.Change = false;
                        if (info.dockItem.Title.IndexOf("[*]") == 0)
                        {
                            var newtitle = info.dockItem.Title.Substring(3);
                            info.dockItem.Title = info.dockItem.TabText = newtitle;
                        }
                    }
                }
            }
        }
        void I_IDE.SaveCurFile()
        {
            SaveFile(curFile);
        }

        void I_IDE.SaveAllFile()
        {
            foreach(var doc in opendocs)
            {
                if(doc.Value.Change)
                {
                    SaveFile(doc.Key);
                }
            }
        }
    }
}
